package com.barryredmond.javamelibchecker;

import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;


/**
 * <p>
 * The AboutScreen is a Canvas which shows the MTE Logo and some information
 * about the MTE
 * </p>
 * 
 * The AboutScreen has 3 sections, the Mobile Trail Explorer (MTE) Logo/Image at
 * the top, followed by an "About" section, and finally a "Useage" section.<br>
 * 
 * Both the About and Useage sections consist of an underlined 'Title' followed
 * by multiple lines of text.
 * 
 * @author Barry Redmond
 */
public final class AboutScreen extends Canvas {

    /**
     * The size margin to draw when margins are needed.
     */
    private static final int MARGIN = 5;
    
    private static final String APPLICATION_WEB_SITE_URL = "http://code.google.com /p/java-me-api-checker/"; 

    /**
         * The default font to use for drawing the messages.
         */
    private static final Font DEFAULT_SIMPLE_FONT = Font.getDefaultFont();

    private static final String[] aboutText = new String[]{ "JavaME API Checher",
            "Version: 1.1", "Copyright (C) 2007 - 2009", "Barry Redmond",
            "", "Licensed under the GPL", "", "For more information visit:",
            APPLICATION_WEB_SITE_URL, "or",
            "barryredmond.com" };

    private static final String[] featureText = new String[]{
            "If there are other APIs you think should be included in this Checker, or you think there is an " +
            "error in the output on your device, please note it on "+APPLICATION_WEB_SITE_URL+", stating the APIs and Devices in question."};

    private static final String[] helpText = new String[]{
            "All checked APIs are written to the screen once, either in the \"Supported\" section, or in " +
            "the \"NOT Supported\" section. If an API is not there it has not been checked by this application. " +
            "In that case, please contact me with the spesific API and I'll try and include it in the next release." };

    /**
         * <p>
         * The titles of the different sections
         * </p>
         * {@link AboutScreen#TITLES}[n] is the title corrosponding to
         * {@link AboutScreen#MESSAGES}[n]<br>
         * Both {@link AboutScreen#TITLES} and {@link AboutScreen#MESSAGES} must
         * NOT be null, and must have the same number of elements.
         */
    private static final String[] TITLES = new String[]{ "About", "Useage", "Help" };

    /**
         * <p>
         * The text for the different sections
         * </p>
         * {@link AboutScreen#MESSAGES}[n] is the text corrosponding to
         * {@link AboutScreen#TITLES}[n]<br>
         * Both {@link AboutScreen#TITLES} and {@link AboutScreen#MESSAGES} must
         * NOT be null, and must have the same number of elements.
         */
    private static final String[][] MESSAGES = new String[][]{ aboutText, featureText, helpText };


    private int yPos;

    // this is calculated the first time the paint(Graphics) method is
    // called.
    private int totalHeight;

    // Used to decide if we should set the 'totalHeight' property.
    private boolean firstTime = true;

    private String[][] formattedMessages;
    
    private Displayable previousScreen;

    /** Creates a new instance of AboutScreen */
    public AboutScreen(Displayable previous) {
        
        if (TITLES == null || MESSAGES == null
                || TITLES.length != MESSAGES.length) {
            throw new IllegalStateException( "There was a problem with the coding of the " 
                    + this.getClass().getName()
                    + " class. neither titles, nor messages may be null, and they both must have the same number of elements");
        }
        
        this.previousScreen = previous;

        this.yPos = 0;

        this.formattedMessages = new String[MESSAGES.length][];
        for (int i = 0; i < MESSAGES.length; i++) {
            formattedMessages[i] = formatMessage(MESSAGES[i], this.getWidth());
        }
    }

    /**
     * <p>
     * Takes an array of messages and a 'Screen-width' and returns the same
     * messages, but any string in that that is wider than 'width' will be
     * split up into 2 or more Strings that will fit on the screen
     * </p>
     * 
     * 'Spliting' up a String is done on the basis of Words, so if a single
     * WORD is longer than 'width' it will be on a Line on it's own, but
     * that line WILL be WIDER than 'width'
     * 
     * @param message
     * @param width
     *                the maximum width a string may be before being split
     *                up.
     * @return
     */
    private String[] formatMessage(String[] message, int width) {
      Vector result = new Vector(message.length);
      for (int i = 0; i < message.length; i++) {
          if (DEFAULT_SIMPLE_FONT.stringWidth(message[i]) <= width) {
              result.addElement(message[i]);
          } else {
              String[] splitUp = StringUtil.chopStrings(message[i], " ",
                      AboutScreen.DEFAULT_SIMPLE_FONT, width);
              for (int j = 0; j < splitUp.length; j++) {
                  result.addElement(splitUp[j]);
              }
          }
      }

      String[] finalResult = new String[result.size()];
      for (int i = 0; i < finalResult.length; i++) {
          finalResult[i] = (String) result.elementAt(i);
      }
      return finalResult;
    }

    protected void paint(Graphics g) {
      int width = this.getWidth();

      // Fill in the background White
      g.setColor(0xFFFFFF); // White
      g.fillRect(0, 0, width, this.getHeight());

      int y = yPos;
      y += MARGIN;

        /*
      if (this.logo != null) {
          g.drawImage(this.logo, width / 2, y, Graphics.TOP
                  | Graphics.HCENTER);
          y += logo.getHeight() + MARGIN;
      }
*/
      g.setColor(0x0); // Black

      // Write the title "About"
      final Font titleFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD
              | Font.STYLE_UNDERLINED, Font.SIZE_LARGE);

      /*
         * FIXME: currently paints ALL the text, even if there is (a lot) more
         * than can fit on the screen. (must do this first time to assess
         * 'height', but shouldn't need to do it for any other repaint
         */
      for (int i = 0; i < TITLES.length; i++) {
          final int basicFontHeight = DEFAULT_SIMPLE_FONT.getHeight();
          final int titleFontHeight = titleFont.getHeight();
          // Write out the 'message' heading
          g.setFont(titleFont);
          final String title = TITLES[i];
          int stringWidth = g.getFont().stringWidth(title);
          g.drawString(title, (width - stringWidth) / 2, y, 0);
          y += titleFontHeight;

          // Write out the 'message' text.
          g.setFont(DEFAULT_SIMPLE_FONT);
          for (int j = 0; j < this.formattedMessages[i].length; j++) {
              final String message = this.formattedMessages[i][j];
              stringWidth = g.getFont().stringWidth(message);
              g.drawString(message, (width - stringWidth) / 2, y, 0);
              y += basicFontHeight;
          }
          y += basicFontHeight;
      }

      // Set the total-Height the first time
      if (firstTime) {
          totalHeight = y + MARGIN;
          firstTime = false;
      }
    }

    /** Handle all keyPressed-events */
    public void keyPressed(int keycode) {
      if (this.getGameAction(keycode) == UP) {
          upPressed();
      } else if (this.getGameAction(keycode) == DOWN) {
          downPressed();
      } else {
          // Exit on ANY other key press.
          Display.getDisplay(LibCheckerMIDlet.getMIDlet()).setCurrent(previousScreen);
      }
    }

    /** Handle all keyRepeaded-events */
    public void keyRepeated(int keycode) {
      if (this.getGameAction(keycode) == UP) {
          upPressed();
      } else if (this.getGameAction(keycode) == DOWN) {
          downPressed();
      }
    }

    /**
         * <p>
         * Pan the screen up if an Up-Key is pressed
         * </p>
         */
    private void upPressed() {
      yPos += 20;
      if (yPos > 0) {
          yPos = 0;
      }
      this.repaint();
    }

    /**
         * <p>
         * Pan the screen down if a Down-Key is pressed
         * </p>
         */
    private void downPressed() {
      yPos -= 20;
      if (yPos < this.getHeight() - this.totalHeight) {
          yPos = this.getHeight() - this.totalHeight;
      }
      this.repaint();
    }

}
